package io.yizoo.system.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dingtalkcontact_1_0.models.GetUserHeaders;
import com.aliyun.dingtalkoauth2_1_0.Client;
import com.aliyun.dingtalkoauth2_1_0.models.*;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;
import com.dingtalk.api.request.OapiV2UserGetuserinfoRequest;
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
import com.dingtalk.api.response.OapiV2UserGetuserinfoResponse;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import io.elm.core.CoreController;
import io.elm.core.saas.DSContext;
import io.elm.core.security.JwtUtils;
import io.yizoo.business.entity.biz_hrm_ei_basic;
import io.yizoo.business.entity.biz_hrm_ei_rel_org;
import io.yizoo.core.ConfigUtil;
import io.yizoo.core.LoginDingtalkService;
import io.yizoo.core.message.MessageContext;
import io.yizoo.core.message.MessageFactory;
import io.yizoo.core.message.MessageService;
import io.yizoo.system.entity.*;
import io.yizoo.system.util.StringUtil;
import io.yizoo.system.util.dingtalk.DdConfigSign;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("system/login/dingtalk")
public class login_dingTalkController extends CoreController{

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    private LoginDingtalkService dingtalkService;
    @Autowired
    private io.yizoo.system.mapper.sys_menuMapper sys_menuMapper;
    @Autowired
    private MessageFactory messageFactory;

    Logger logger = LoggerFactory.getLogger(login_dingTalkController.class);

    @RequestMapping("/authConfig")
    public Map getAuthConfig(@RequestParam("key") String key) {
        Map<String,String> result = new HashMap<>();
        Map<String, Object> dingTalkConfig = ConfigUtil.getConfig(key);
        if (dingTalkConfig == null) {
            return null;
        }
        result.put("client_id", dingTalkConfig.get("client_id").toString());
        if (dingTalkConfig.get("corp_id") != null) {
            result.put("corp_id", dingTalkConfig.get("corp_id").toString());
        }
        if (dingTalkConfig.get("agent_id") != null) {
            result.put("agent_id", dingTalkConfig.get("agent_id").toString());
        }
        UUID uuid = UUID.randomUUID();
        result.put("nonceStr",uuid.toString());
        result.put("timestamp", System.currentTimeMillis() + "");
        String accessToken = dingtalkService.getAccessToken(key);
        if (StringUtils.isEmpty(accessToken)) {
            throw new RuntimeException("获取 access token 失败");
        }
        String jsapiTicket = getJsapiTicket(accessToken, key);
        try {
            String sign = DdConfigSign.sign(jsapiTicket, result.get("nonceStr"), Long.parseLong(result.get("timestamp").toString()), "http://www.snbg365.com/v/system/login?loginType=dingtalk&key=sn");
            result.put("signature", sign);
        } catch (Exception e) {
            throw new RuntimeException("dd config 签名获取失败",e);
        }
//        new DingCallbackCrypto()
//        result.put("signature", DingCallbackCrypto.getSignature(result.get("timestamp"), result.get("nonceStr"), key));
        return result;

    }
    public String getJsapiTicket(String accessToken,String key) {
        LoadingCache<String, String> loadingCache = CacheBuilder.newBuilder()
                .maximumSize(DSContext.DATA_SET.size())
                .expireAfterWrite(2, TimeUnit.HOURS)
                .build(new CacheLoader<String, String>() {
                    @Override
                    public String load(String s) throws Exception {
                        try {
                            Client client = dingtalkService.authClient(key);
                            CreateJsapiTicketHeaders createJsapiTicketHeaders = new CreateJsapiTicketHeaders();
                            createJsapiTicketHeaders.xAcsDingtalkAccessToken = accessToken;
                            CreateJsapiTicketResponse jsapiTicketWithOptions = client.createJsapiTicketWithOptions(createJsapiTicketHeaders, new RuntimeOptions());
                            return jsapiTicketWithOptions.getBody().getJsapiTicket();
                        } catch (Exception e) {
                            logger.error("jsapi ticket 获取失败错误原因：", e);
                            throw new RuntimeException("jsapi ticket 获取失败",e);
                           // return null;

                        }
                    }
                });
        return loadingCache.getUnchecked(key);

    }
//
//    @RequestMapping("/auth")
//    public String auth(@RequestParam("key") String key) {
//        System.out.println("【AAAA】dingtalk/callback/auth");
//        System.out.println("key :" + key);
//        List<Map<String, Object>> dataSet = DSContext.DATA_SET;
//        String clientId = "";
//        String secret = "";
//        String corpId = "";
//       // if (ConfigUtil.getConfig(key, dataSet)) return null;
//
//
//        return null;
//    }





    /**
     *{
     *     "key":"sennuo",
     *     "title":"测试标题",
     *     "content":"#### 你有一条数据需要处理，点击连接查看",
     *     "toTarget":["126218535726248336"]
     *
     * }
     * title 消息标题
     * sendUserId 发送人 用来确定企业及保存发送信息
     * content 消息内容
     * toTarget 必填 接收人id( thirdId)
     * @param jsonStr
     * @return
     * @throws Exception
     */
    @RequestMapping("/sendMsg")
    public Object sendMsg(@RequestBody String jsonStr) throws Exception {
        JSONObject param = JSONObject.parseObject(jsonStr);
        String title = param.getString("title");
        String content = param.getString("content");
        JSONArray toTarget = param.getJSONArray("toTarget");
        String sendUserId = param.getString("sendUserId");
        String currentKey = Ctor.getCurrentKey();
        MessageContext context = new MessageContext(
                currentKey,
                toTarget.toJavaList(String.class),
                title,
                content,
                false,
                sendUserId
        );
        MessageService instance = messageFactory.getInstance(sendUserId);
        return instance.sendMsg(context);
    }

    /**
     * 获取用户token
     * @param authCode
     * @return
     * @throws Exception
     */
    //接口地址：注意/auth与钉钉登录与分享的回调域名地址一致
    @RequestMapping(value = "/auth")
    public Object auth(@RequestParam("authCode")String authCode, @RequestParam("key") String key) throws Exception {
        Map<String, Object> dingTalkConfig = ConfigUtil.getConfig(key);
        if (dingTalkConfig== null) {
            return "";
        }
        String accessToken = dingtalkService.getAccessToken(key);
        DingTalkClient userClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo");
        OapiV2UserGetuserinfoRequest req = new OapiV2UserGetuserinfoRequest();
        req.setCode(authCode);
        OapiV2UserGetuserinfoResponse rsp = userClient.execute(req, accessToken);
        System.out.println(rsp.getBody());
        if (rsp.getErrcode() == 0) {
            String name = rsp.getResult().getName();
            String thirdId = rsp.getResult().getUserid();
            DSContext.clearDataSourceType();
            DSContext.setDataSourceType(key);
            return preLogin(thirdId,name, key);
        }
        return  null;

    }

    private Object preLogin(String thirdId,String nickName, String key) {

        sys_user user_mod = Ctor.HMapper.GetSingle(sys_user.class,
                Ctor.DMaker().Selector
                        .putFactorItem("id", nickName)
                        .From(sys_user.class).Where("and nick_name=#{id}").GetFactor()
        );
        String userName = user_mod.getUser_name();
        sys_user_third sys_user_third = Ctor.HMapper.GetSingle(sys_user_third.class,
                Ctor.DMaker().Selector
                        .From(sys_user_third.class)
                        .putFactorItem("id", thirdId)
                        .IsWhere("and third_id = #{id}",thirdId)
                        .Limit("limit 1")
                        .GetFactor());
        if (sys_user_third == null) {
            sys_user_third = new sys_user_third();
            sys_user_third.setId(UUID.randomUUID().toString());
            sys_user_third.setUser_id(user_mod.getId());
            sys_user_third.setThird_id(thirdId);
            sys_user_third.setThird_type("dingTalk");
            Ctor.HMapper.Upsert(sys_user_third.class,JSON.toJSONString(sys_user_third));
        }
        final String token = jwtUtils.generateToken(userName+"."+key);
        userName = Ctor.GetCutUsername(userName);
        //若有人员关联，那么几个字段值用人员表记录的对应字段值
        boolean eiOrgExist = false;
        List<Map<String,Object>> check_ei = Ctor.CoreMapper.USelect(
                Ctor.DMaker().Selector
                        .putFactorItem("id", user_mod.getId())
                        .Select("uu.*,ei.id AS ei_id,ei.name AS ei_name,ei.sex AS ei_sex,ei.phone AS ei_phone,oo.id AS ei_org_id")
                        .From(sys_user.class,"uu")
                        .LeftJoin(biz_hrm_ei_basic.class,"ei","ei.emp_code = uu.emp_code")
                        .LeftJoin(biz_hrm_ei_rel_org.class,"rr","rr.ei_id = ei.id AND rr.pm='1' ")
                        .LeftJoin(sys_org.class,"oo","oo.id = rr.org_id ")
                        .Where("AND uu.id = #{id}","id")
                        .GetFactor());
        if(check_ei.size()==1 && check_ei.get(0).get("ei_id")!=null){
            Map<String,Object> item = check_ei.get(0);
            if(item.get("ei_name")!=null){user_mod.setNick_name(item.get("ei_name").toString());}
            if(item.get("ei_org_id")!=null){user_mod.setDept_id(item.get("ei_org_id").toString());eiOrgExist = true;}
            //if(item.get("ei_phone")!=null){user_mod.setPhonenumber(item.get("ei_phone").toString());}
            //if(item.get("ei_sex")!=null){user_mod.setSex(item.get("ei_sex").toString());}
        }
        sys_org org_mod = Ctor.HMapper.GetSingle(sys_org.class,
                Ctor.DMaker().Selector.From(sys_org.class, "t")
                        .putFactorItem("id", nickName)
                        .LeftJoin(sys_user.class, "a", "a.dept_id=t.id")
                        .Where("and a.user_name=#{id}").GetFactor()
        );
        if(eiOrgExist){
            org_mod = Ctor.HMapper.GetSingle(sys_org.class,
                    Ctor.DMaker().Selector.From(sys_org.class, "t")
                            .putFactorItem("id", user_mod.getDept_id())
                            .Where("and t.id=#{id}").GetFactor()
            );
        }
        Object roles = Ctor.CoreMapper.USelect(
                Ctor.DMaker(JSON.toJSONString(user_mod)).Selector.From(sys_role.class, "t")
                        .Select("t.*")
                        .putFactorItem("user_id", user_mod.getId())
                        .LeftJoin(sys_role_rel_user.class, "a", "a.role_id=t.id")
                        .Where("and a.user_id=#{user_id}").GetFactor()
        );
        Object menu_data = sys_menuMapper.SelectUserMenuTree(
                Ctor.DMaker().Selector.putFactorItem("user_id", user_mod.getId()).GetFactor()
        );
        Map<String, Object> user = new HashMap<>();
        user.put("thirdId", sys_user_third.getThird_id());
        user.put("name", user_mod.getNick_name());
        user.put("id", user_mod.getId());
        user.put("loginType","dingtalk");
        Map<String, Object> map = JsonResult(
                new KV("token", token),
                new KV("success", true),
                new KV("authpage", ""),
                new KV("menu", menu_data),
                new KV("user",
                        user),
                new KV("org",
                        new KV("name", org_mod == null ? "" : org_mod.getName())),
                new KV("role", roles),
                new KV("system",
                        new KV("path", "/system/main"),
                        new KV("name", "主页"))
        );
        System.out.println("ding talk login result: "+JSON.toJSONString(map));

        return map;
    }



    public static com.aliyun.dingtalkcontact_1_0.Client contactClient() throws Exception {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkcontact_1_0.Client(config);
    }

    /**
     * 获取用户个人信息
     * @param accessToken
     * @return
     * @throws Exception
     */
    public String getUserinfo(String accessToken) throws Exception {
        com.aliyun.dingtalkcontact_1_0.Client client = contactClient();
        GetUserHeaders getUserHeaders = new GetUserHeaders();
        getUserHeaders.xAcsDingtalkAccessToken = accessToken;
        //获取用户个人信息，如需获取当前授权人的信息，unionId参数必须传me
        String me = JSON.toJSONString(client.getUserWithOptions("me", getUserHeaders, new RuntimeOptions()).getBody());
        System.out.println(me);
        return me;
    }
}
